#include "VSPartialAnimBlend.h"
#include "VSSkelectonMeshNode.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSPartialAnimBlend,VSAnimBlendFunction)
static bool gs_bStreamRegistered_VSPartialAnimBlend= VSPartialAnimBlend::RegisterMainFactory();
bool VSPartialAnimBlend::ms_bRegisterMainFactory = false;
bool VSPartialAnimBlend::RegisterMainFactory()
{
	if (!ms_bRegisterMainFactory)
	{ 
		VSMain::AddInitialFuntion(VSPartialAnimBlend::InitialClassFactory); 
		ms_bRegisterMainFactory = true;
	} 
	return ms_bRegisterMainFactory;

}
bool VSPartialAnimBlend::InitialClassFactory()
{
	ms_ClassFactory.AddElement(ms_Type.GetName(),FactoryFunc);

	return 1;
}
VSObject * VSPartialAnimBlend::FactoryFunc()
{
	return VS_NEW VSPartialAnimBlend;

}
VSPartialAnimBlend::~VSPartialAnimBlend()
{
	
	m_WeigthSetName.Clear();
}
VSPartialAnimBlend::VSPartialAnimBlend()
{
	m_bIsReady = false;
	m_WeigthSetName.Clear();
}
VSPartialAnimBlend::VSPartialAnimBlend(const VSUsedName & ShowName,VSAnimTree * pAnimTree)
:VSAnimBlendFunction(ShowName,pAnimTree)
{
	
	VSString InputName0 = _T("Child0");
	VSInputNode * pInputNode = NULL;
	pInputNode = VS_NEW VSInputNode(VSPutNode::AVT_ANIM,InputName0,this);
	VSMAC_ASSERT(pInputNode);
	m_pInput.AddElement(pInputNode);

	m_WeigthSetName.AddElement(VSString::ms_StringNULL);

	VSString InputName1 = _T("Child1");
	pInputNode = NULL;
	pInputNode = VS_NEW VSInputNode(VSPutNode::AVT_ANIM,InputName1,this);
	VSMAC_ASSERT(pInputNode);
	m_pInput.AddElement(pInputNode);
	m_WeigthSetName.AddElement(VSString::ms_StringNULL);

	m_bIsReady = false;
}
void VSPartialAnimBlend::AddInputNode()
{
	VSString InputName = _T("Child");
	VSString ID = IntToString(m_pInput.GetNum()); 
	InputName += ID;
	VSInputNode * pInputNode = NULL;
	pInputNode = VS_NEW VSInputNode(VSPutNode::AVT_ANIM,InputName,this);
	VSMAC_ASSERT(pInputNode);
	m_pInput.AddElement(pInputNode);

	m_WeigthSetName.AddElement(VSString::ms_StringNULL);
}
void VSPartialAnimBlend::DeleteInputNode()
{
	if (m_pInput.GetNum() > 2)
	{
		VSInputNode * pInputNode = m_pInput[m_pInput.GetNum() - 1];

		m_pInput.Erase(m_pInput.GetNum() - 1);
		if (!pInputNode)
		{
			return ;
		}
		VSMAC_DELETE(pInputNode);

		m_WeigthSetName.Erase(m_WeigthSetName.GetNum() - 1);
	}
}
void VSPartialAnimBlend::AddWeightSet(unsigned int i,const VSUsedName & WeightSetName)
{
	if (i >= m_WeigthSetName.GetNum())
	{
		return ;
	}
	
	const VSSkelectonMeshNode * pMesh = GetSkelectonMeshNode();
	VSMAC_ASSERT(pMesh);
	if (!pMesh)
	{
		return ;
	}

	const VSAnimSet * pAnimSet = pMesh->GetAnimSet();
	VSMAC_ASSERT(pAnimSet);
	if (!pAnimSet)
	{
		return;
	}
	VSWeightSet * pWeightSet = pAnimSet->GetWeightSet(WeightSetName);
	if(!pWeightSet)
		return ;
	m_WeigthSetName[i] = WeightSetName;
}
unsigned int VSPartialAnimBlend::DiskUse()const
{
	unsigned int Used = VSAnimBlendFunction::DiskUse();


	Used += sizeof(unsigned int);


	for (unsigned int i = 0 ; i < m_WeigthSetName.GetNum() ; i++)
	{
		Used += m_WeigthSetName[i].DiskUse();
	}
	
	return Used;
}
bool VSPartialAnimBlend::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSAnimBlendFunction::Save(rStream,iSaveUse))
		return 0;

	unsigned int uiWeightNameNum = m_WeigthSetName.GetNum();
	if(!rStream.Write(&uiWeightNameNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);


	for (unsigned int i = 0 ; i < m_WeigthSetName.GetNum() ; i++)
	{
		m_WeigthSetName[i].Save(rStream,iSaveUse);
	}
	
	return 1;
}
bool VSPartialAnimBlend::Load(VSStream & rStream,unsigned int &iSaveUse)
{	
	if(!VSAnimBlendFunction::Load(rStream,iSaveUse))
		return 0;
	unsigned int uiWeightNameNum = 0;
	if(!rStream.Read(&uiWeightNameNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_WeigthSetName.SetBufferNum(uiWeightNameNum);
	

	for (unsigned int i = 0 ;  i < uiWeightNameNum ; i++)
	{
		m_WeigthSetName[i].Load(rStream,iSaveUse);
	}
	
	return 1;
}
bool VSPartialAnimBlend::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSPartialAnimBlend* Temp = DynamicCast<VSPartialAnimBlend>(pObject); 
	if(!Temp)
		return 0;
	if(VSAnimBlendFunction::Clone(pObject,uiType))
	{
		m_WeigthSetName = Temp->m_WeigthSetName;
		m_bIsReady = false;
		return 1;

	}
	else
	{
		return 0;
	}

}
bool VSPartialAnimBlend::PostLoad( void * pDate)
{
	for (unsigned int i = 0 ; i < m_WeigthSetName.GetNum() ; i++)
	{
		AddWeightSet(i,m_WeigthSetName[i]);
	}
	return 1;
}
bool VSPartialAnimBlend::ComputeOutBoneMatrix(double dAppTime)
{
	ComputeWeight();

	unsigned int uiBoneNum = 0;
	for ( unsigned int i = 0 ; i < m_pInput.GetNum() ; i++)
	{
		VSInputNode* pInputNode = GetInputNode(i);
		VSAnimFunction *pAnimBaseFunction = (VSAnimFunction *)pInputNode->GetOutputLink()->GetOwner();
		if (!pAnimBaseFunction)
		{
			return false;
		}
		if (i == 0)
		{
			uiBoneNum = pAnimBaseFunction->m_BoneOutPut.GetNum();
		}
		else
		{
			if ( uiBoneNum != pAnimBaseFunction->m_BoneOutPut.GetNum())
			{
				return false;
			}
		}

		for(unsigned int j = 0 ; j < uiBoneNum ; j++)
		{
			if (i == 0)
			{
				m_BoneOutPut[j] = pAnimBaseFunction->m_BoneOutPut[j] * m_Weight[i][j];
			}
			else
			{
				m_BoneOutPut[j] = m_BoneOutPut[j] + pAnimBaseFunction->m_BoneOutPut[j] * m_Weight[i][j];
			}
		}
	}
	return 1;
}
bool VSPartialAnimBlend::ComputePara(double dAppTime)
{
	return 1;
}
void VSPartialAnimBlend::ComputeWeight()
{
	if (!m_bIsReady)
	{
		const VSSkelectonMeshNode * pMesh = GetSkelectonMeshNode();
		VSMAC_ASSERT(pMesh);
		if (!pMesh)
		{
			return ;
		}

		const VSAnimSet * pAnimSet = pMesh->GetAnimSet();
		VSMAC_ASSERT(pAnimSet);
		if (!pAnimSet)
		{
			return;
		}
		VSSkelecton * pSkelecton = pMesh->GetSkelecton();
		VSMAC_ASSERT(pSkelecton);
		if (!pSkelecton)
		{
			return ;
		}
		m_Weight.SetBufferNum(m_WeigthSetName.GetNum());
		for (unsigned int i = 0 ; i < m_WeigthSetName.GetNum() ; i++)
		{
			VSWeightSet * pWeightSet = pAnimSet->GetWeightSet(m_WeigthSetName[i]);
			if(!pWeightSet)
				return ;
			m_Weight[i].SetBufferNum(pSkelecton->GetBoneNum());
			for(unsigned int j = 0 ; j < pSkelecton->GetBoneNum() ; i++)
			{
				VSBoneNode * pBone = pSkelecton->GetBoneNode(j);

				VSBoneWeight * pBoneWeight = pWeightSet->GetBoneWeight(pBone->m_cName);
				m_Weight[i][j] = pBoneWeight->m_fWeight;
			}
			
			
		}
		
		for (unsigned int i = 0 ; i < pSkelecton->GetBoneNum() ; i++)
		{

			VSREAL fSum = 0;
			for(unsigned int j = 0 ; j < m_Weight.GetNum() ; j++)
			{
				fSum += m_Weight[j][i];
			}
			if (ABS(fSum) < EPSILON_E4)
			{
				continue;
			}
			for(unsigned int j = 0 ; j < m_Weight.GetNum() ; j++)
			{
				m_Weight[j][i] =  m_Weight[j][i] / fSum;
			}
		}
		m_bIsReady = true;
	}
}